/* # Licensed Materials - Property of IBM # Copyright IBM Corp. 2016,2017 */ package com.ibm.streamsx.topology.internal.streaminganalytics; import static com.ibm.streamsx.topology.internal.gson.GsonUtilities.jstring; import static com.ibm.streamsx.topology.internal.streaminganalytics.VcapServices.getVCAPService; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import javax.xml.bind.DatatypeConverter; import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.auth.AUTH; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.ibm.streamsx.topology.context.remote.RemoteContext; import com.ibm.streamsx.topology.internal.context.remote.DeployKeys; public class RestUtils { public static String getStatusURL(JsonObject credentials) { StringBuilder sb = new StringBuilder(500); sb.append(jstring(credentials, "rest_url")); sb.append(jstring(credentials, "status_path")); return sb.toString(); } public static String getJobSubmitURL(JsonObject credentials, File bundle) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(500); sb.append(jstring(credentials, "rest_url")); sb.append(jstring(credentials, "jobs_path")); sb.append("?"); sb.append("bundle_id="); sb.append(URLEncoder.encode(bundle.getName(), StandardCharsets.UTF_8.name())); return sb.toString(); } public static void checkInstanceStatus(CloseableHttpClient httpClient, JsonObject service) throws ClientProtocolException, IOException { final String serviceName = jstring(service, "name"); final JsonObject credentials = service.getAsJsonObject("credentials"); String url = getStatusURL(credentials); String apiKey = getAPIKey(credentials); HttpGet getStatus = new HttpGet(url); getStatus.addHeader(AUTH.WWW_AUTH_RESP, apiKey); JsonObject jsonResponse = getGsonResponse(httpClient, getStatus); RemoteContext.REMOTE_LOGGER.info("Streaming Analytics service (" + serviceName + "): instance status response:" + jsonResponse.toString()); if (!"true".equals(jstring(jsonResponse, "enabled"))) throw new IllegalStateException("Service is not enabled!"); if (!"running".equals(jstring(jsonResponse, "status"))) throw new IllegalStateException("Service is not running!"); } public static String getAPIKey(JsonObject credentials) { String userid = jstring(credentials, "userid"); String password = jstring(credentials, "password"); String api_creds = userid + ":" + password; String apiKey = "Basic " + DatatypeConverter.printBase64Binary(api_creds.getBytes(StandardCharsets.UTF_8)); return apiKey; } public static JsonObject getGsonResponse(CloseableHttpClient httpClient, HttpRequestBase request) throws IOException, ClientProtocolException { request.addHeader("accept", ContentType.APPLICATION_JSON.getMimeType()); CloseableHttpResponse response = httpClient.execute(request); JsonObject jsonResponse; try { HttpEntity entity = response.getEntity(); if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { final String errorInfo; if (entity != null) errorInfo = " -- " + EntityUtils.toString(entity); else errorInfo = ""; throw new IllegalStateException( "Unexpected HTTP resource from service:" + response.getStatusLine().getStatusCode() + ":" + response.getStatusLine().getReasonPhrase() + errorInfo); } if (entity == null) throw new IllegalStateException("No HTTP resource from service"); Reader r = new InputStreamReader(entity.getContent()); jsonResponse = new Gson().fromJson(r, JsonObject.class); EntityUtils.consume(entity); } finally { response.close(); } return jsonResponse; } /** * Submit an application bundle to execute as a job. */ public static JsonObject postJob(CloseableHttpClient httpClient, JsonObject service, File bundle, JsonObject jobConfigOverlay) throws ClientProtocolException, IOException { final String serviceName = jstring(service, "name"); final JsonObject credentials = service.getAsJsonObject("credentials"); String url = getJobSubmitURL(credentials, bundle); HttpPost postJobWithConfig = new HttpPost(url); postJobWithConfig.addHeader("accept", ContentType.APPLICATION_JSON.getMimeType()); postJobWithConfig.addHeader(AUTH.WWW_AUTH_RESP, getAPIKey(credentials)); FileBody bundleBody = new FileBody(bundle, ContentType.APPLICATION_OCTET_STREAM); StringBody configBody = new StringBody(jobConfigOverlay.toString(), ContentType.APPLICATION_JSON); HttpEntity reqEntity = MultipartEntityBuilder.create().addPart("sab", bundleBody) .addPart(DeployKeys.JOB_CONFIG_OVERLAYS, configBody).build(); postJobWithConfig.setEntity(reqEntity); JsonObject jsonResponse = getGsonResponse(httpClient, postJobWithConfig); RemoteContext.REMOTE_LOGGER.info("Streaming Analytics service (" + serviceName + "): submit job response:" + jsonResponse.toString()); return jsonResponse; } }